using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;

using ImageRecognition2.CustomControls;

namespace ImageRecognition2.Forms
{
    /// <summary>
    /// Warp
    /// </summary>
    public partial class FormWarp : Form
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="FormWarp"/> class.
        /// </summary>
        public FormWarp()
        {
            InitializeComponent();
        }

        Image img;

        /// <summary>
        /// Offsets the filter slow.
        /// </summary>
        /// <param name="b">The b.</param>
        /// <param name="offset">The offset.</param>
        /// <returns></returns>
        public static bool OffsetFilterSlow(Bitmap b, Point[,] offset)
        {
            Bitmap bSrc = (Bitmap)b.Clone();

            int scanline = b.Width*3;

            int nOffset = scanline - b.Width * 3;
            int nWidth = b.Width;
            int nHeight = b.Height;
            int p = 0;

            int xOffset, yOffset;

            for (int y = 0; y < nHeight; ++y)
            {
                for (int x = 0; x < nWidth; ++x)
                {
                    xOffset = offset[x, y].X;
                    yOffset = offset[x, y].Y;

                    if (y + yOffset >= 0 && y + yOffset < nHeight && x + xOffset >= 0 && x + xOffset < nWidth)
                    {
                        Color c =bSrc.GetPixel((x + xOffset), (y + yOffset));
                        b.SetPixel(x,y, c);
                    }

                    p += 3;
                }
                p += nOffset;
            }


            return true;
        }

        /// <summary>
        /// Offsets the filter.
        /// </summary>
        /// <param name="b">The b.</param>
        /// <param name="offset">The offset.</param>
        /// <returns></returns>
        public static bool OffsetFilter(Bitmap b, Point[,] offset)
        {
            Bitmap bSrc = (Bitmap)b.Clone();

            // GDI+ still lies to us - the return format is BGR, NOT RGB.
            BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int scanline = bmData.Stride;

            System.IntPtr Scan0 = bmData.Scan0;
            System.IntPtr SrcScan0 = bmSrc.Scan0;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;
                byte* pSrc = (byte*)(void*)SrcScan0;

                int nOffset = bmData.Stride - b.Width * 3;
                int nWidth = b.Width;
                int nHeight = b.Height;

                int xOffset, yOffset;

                for (int y = 0; y < nHeight; ++y)
                {
                    for (int x = 0; x < nWidth; ++x)
                    {
                        xOffset = offset[x, y].X;
                        yOffset = offset[x, y].Y;

                        if (y + yOffset >= 0 && y + yOffset < nHeight && x + xOffset >= 0 && x + xOffset < nWidth)
                        {
                            p[0] = pSrc[((y + yOffset) * scanline) + ((x + xOffset) * 3)];
                            p[1] = pSrc[((y + yOffset) * scanline) + ((x + xOffset) * 3) + 1];
                            p[2] = pSrc[((y + yOffset) * scanline) + ((x + xOffset) * 3) + 2];
                        }

                        p += 3;
                    }
                   // p += nOffset;
                }
            }

            b.UnlockBits(bmData);
            bSrc.UnlockBits(bmSrc);

            return true;
        }
        
        Point[,] G = new Point[10, 10];
        Point[,] GImg = new Point[480, 640];

        /// <summary>
        /// Handles the Load event of the Form1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Form1_Load(object sender, EventArgs e)
        {
            img = Bitmap.FromFile("004.bmp");
            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    G[i, j] = new Point(0, 0);
                }
            }
            isControlPointSelected = false;
        }

        /// <summary>
        /// Calcs the offsets.
        /// </summary>
        private void CalcOffsets()
        {
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    for (int m = 0; m < 48; m++)
                    {
                        for (int n = 0; n < 64; n++)
                        {
                            double xfrac = (double)1 / 48.0;
                            double yfrac = (double)1 / 64.0;
                            double s = (G[i + 1, j].X - G[i, j].X) * m * xfrac + G[i, j].X;
                            double t = (G[i + 1, j].Y - G[i, j].Y) * m * xfrac + G[i, j].Y;
                            double u = (G[i + 1, j + 1].X - G[i, j + 1].X) * m * xfrac + G[i, j+1].X;
                            double v = (G[i + 1, j + 1].Y - G[i, j + 1].Y) * m * xfrac + G[i, j+1].Y;
                            GImg[i * 48 + m, j * 64 + n].X = -(int)( s + (u - s) * n * yfrac);
                            GImg[i * 48 + m, j * 64 + n].Y = -(int)( t + (v - t) * n * yfrac);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Handles the Paint event of the panel1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            if (checkBox2.CheckState == CheckState.Checked)
            {
                Image temp = (Image)img.Clone();
                CalcOffsets();
                OffsetFilter((Bitmap)temp, GImg);
                if (img != null)
                    e.Graphics.DrawImage(temp, new Rectangle(0, 0, panel1.Width, panel1.Height));
            }
            else
            {
                if (img != null)
                    e.Graphics.DrawImage(img, new Rectangle(0, 0, panel1.Width, panel1.Height));
            }
            if (checkBox1.CheckState == CheckState.Checked)
            {
                Pen P = new Pen(Color.Red);
                for (int i = 1; i < 9; i++)
                    for (int j = 1; j < 9; j++)
                    {
                        e.Graphics.DrawLine(P, new Point(i * 48 + G[i, j].X, j * 64 + G[i, j].Y), new Point(i * 48 + G[i, j + 1].X, (j + 1) * 64 + G[i, j + 1].Y));
                        e.Graphics.DrawLine(P, new Point(i * 48 + G[i, j].X, j * 64 + G[i, j].Y), new Point((i + 1) * 48 + G[i + 1, j].X, j * 64 + G[i + 1, j].Y));
                    }
            }
        }

        /// <summary>
        /// Handles the CheckedChanged event of the checkBox1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            panel1.Invalidate(false);
        }

        bool isControlPointSelected;
        Point SelectedGridPoint;
        Point p_Start;

        /// <summary>
        /// Handles the MouseDoubleClick event of the panel1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private void panel1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (isControlPointSelected == false)
            {
                for (int i = 0; i < 10; i++)
                    for (int j = 0; j < 10; j++)
                    {
                        if (Math.Abs(i * 48 + G[i, j].X - e.X) < 5 && Math.Abs(j * 64 + G[i, j].Y - e.Y) < 5)
                        {
                            isControlPointSelected = true;
                            SelectedGridPoint = new Point(i, j);
                            p_Start = new Point(e.X, e.Y);
                        }
                    }
            }
            else
            {
                isControlPointSelected = false;
            }
        }

        /// <summary>
        /// Handles the MouseMove event of the panel1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (isControlPointSelected)
            {
                G[SelectedGridPoint.X, SelectedGridPoint.Y].X += e.X - p_Start.X;
                G[SelectedGridPoint.X, SelectedGridPoint.Y].Y += e.Y - p_Start.Y;
                p_Start.X = e.X; p_Start.Y = e.Y;
                panel1.Invalidate(false);
            }
        }

        /// <summary>
        /// Handles the CheckedChanged event of the checkBox2 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            panel1.Invalidate(false);
        }
    }
}